package com.hcy.controller;

import com.alibaba.fastjson.JSON;
import com.hcy.common.dto.request.DirectionRequestDTO;
import com.hcy.common.dto.request.PushMsgRequestDTO;
import com.hcy.commonn.CommonInfoClient;
import com.hcy.customer.CarLevelInfoRequest;
import com.hcy.customer.CarLevelInfoResponse;
import com.hcy.customer.CustomerPageInfoClient;
import com.hcy.model.CallCarRequestDTO;
import com.hcy.mqclient.message.MessageServiceClient;
import com.hcy.mqmodel.dto.request.PushOrderRequestDTO;
import com.hcy.orderclient.OrderBaseClient;
import com.hcy.orderclient.OrderForDriverClient;
import com.hcy.ordermodel.dto.request.AddOrderRequestDTO;
import com.hcy.ordermodel.dto.request.CancelOrderRequestDTO;
import com.hcy.ordermodel.dto.request.DriverOrderRequestDTO;
import com.hcy.ordermodel.dto.request.UpdateOrderOriginPointRequestDTO;
import com.hcy.ordermodel.dto.response.AddOrderResponseDTO;
import com.hcy.ordermodel.dto.response.SimpleOrderResponseDTO;
import com.hcy.rabbitbasicmodel.common.MyWebSocketMessage;
import com.hcy.rabbitbasicmodel.enums.*;
import com.hcy.rabbitbasicmodel.model.ResponseData;
import com.hcy.rabbitbasicmodel.model.ReturnResult;
import com.hcy.rabbitbasicutils.utils.RedisUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Author huchenying
 * @Description 获取页面信息
 * @Date 2021/12/20 12:52
 **/
@RestController
@RequestMapping("/pageInfo")
public class IndexController {

    private static final Logger logger = LoggerFactory.getLogger(IndexController.class);

    @Autowired
    private CustomerPageInfoClient customerPageInfoClient;
    @Autowired
    private CommonInfoClient commonInfoClient;
    @Autowired
    private MessageServiceClient messageServiceClient;
    @Autowired
    private OrderForDriverClient orderForDriverClient;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private OrderBaseClient orderBaseClient;

    /**
     * 获取展示首页信息
     */
    @PostMapping("/home")
    public ReturnResult home() {
        return ReturnResult.success();
    }

    /**
     * TODO 有那些车型，预计价格
     * TODO 获取个人信息
     */
    @PostMapping("/getCarTypes")
    public ReturnResult getCarTypes(@Validated @RequestBody CarLevelInfoRequest carLevelInfoRequest) {
        logger.info("getCarTypes start ");
        try {
            ResponseData<List<CarLevelInfoResponse>> carInfo = customerPageInfoClient.getCarInfo(carLevelInfoRequest);
            if (carInfo.getCode() != Code.Success) {
                return ReturnResult.fail("系统异常");
            }
            return ReturnResult.success().setData(carInfo.getData());
        } catch (Exception e) {
            logger.error("请求预计价格异常", e);
            return ReturnResult.fail("系统异常");
        }
    }

    /**
     * @Author huchenying
     * @Description 路径规划
     * @Date 2022/3/14 10:37
     **/
    @PostMapping("/direction")
    public ReturnResult direction(@RequestBody DirectionRequestDTO requestDTO) {
        logger.info("direction start param -> {} ", ToStringBuilder.reflectionToString(requestDTO));
        try {
            ResponseData<Object> direction = commonInfoClient.direction(requestDTO);
            if (direction.getCode() == Code.Success) {
                logger.info("res -> {}",ToStringBuilder.reflectionToString(direction.getData()));
                return ReturnResult.success().setData(direction.getData());
            }
            return ReturnResult.fail("系统异常");
        } catch (Exception e) {
            logger.error("请求路线规划异常", e);
            return ReturnResult.fail("系统异常");
        }
    }

    /**
     * @Author huchenying
     * @Description 派单请求
     * @Date 2022/3/15 17:03
     **/
    @PostMapping("/callCar")
    public ReturnResult requestOrder(@Validated @RequestBody CallCarRequestDTO requestDTO) {
        logger.info("requestOrder start param -> {}", ToStringBuilder.reflectionToString(requestDTO));
        AddOrderResponseDTO addOrderResponseDTO = null;
        //判断是否是再次呼叫的订单
        if (StringUtils.isNotEmpty(requestDTO.getOrderNumber())) {
            logger.info("重新呼叫的订单");
            addOrderResponseDTO = new AddOrderResponseDTO();
            DriverOrderRequestDTO requestDTO1 = new DriverOrderRequestDTO();
            requestDTO1.setOrderNumber(requestDTO.getOrderNumber());
            ResponseData<SimpleOrderResponseDTO> simpleOrder = orderForDriverClient.getSimpleOrder(requestDTO1);
            if (simpleOrder.getCode() != Code.Success) {
                logger.error("订单获取失败！");
                return ReturnResult.fail("订单号不存在！");
            }
            SimpleOrderResponseDTO data = simpleOrder.getData();
            BeanUtils.copyProperties(data,addOrderResponseDTO);
        } else {
            // 整理数据，创建订单
            AddOrderRequestDTO addOrderRequestDTO = new AddOrderRequestDTO();
            BeanUtils.copyProperties(requestDTO, addOrderRequestDTO);
            addOrderRequestDTO.setStatus(OrderStatus.START.getCode()); //实时单状态为直接开始
            addOrderRequestDTO.setServiceType(OrderServiceType.CURRENT.getCode());
            ResponseData<AddOrderResponseDTO> addOrderResponseDTOResponseData = orderForDriverClient.addOrder(addOrderRequestDTO);
            if (addOrderResponseDTOResponseData.getCode() != Code.Success) {
                logger.error("订单创建失败！");
                return ReturnResult.fail("系统繁忙，请重试！");
            }
            addOrderResponseDTO = addOrderResponseDTOResponseData.getData();
        }
        //把订单放入缓存
        redisUtils.setOrderCache(addOrderResponseDTO.getOrderNumber(), JSON.toJSONString(addOrderResponseDTO), 5, TimeUnit.HOURS);
        // 这个标识只为了消费时判断是否消费，包括司机接单时判断订单是否有效
        redisUtils.setCallOrderKeepAlive(addOrderResponseDTO.getOrderNumber(), addOrderResponseDTO.getOrderNumber(), 10, TimeUnit.SECONDS);
        // 通过上车的坐标查找到Topic
        DirectionRequestDTO directionRequestDTO = new DirectionRequestDTO();
        directionRequestDTO.setOrigin(requestDTO.getStartLongitude() + "," + requestDTO.getStartLatitude());
        ResponseData<String> belongTopic = commonInfoClient.getBelongTopic(directionRequestDTO);
        logger.info("belongTopic = [{}]", belongTopic);
        //发送消息
        Message message = new Message();
        message.setTopic(belongTopic.getData());
        message.setTags("NOW");
        message.setKeys(addOrderResponseDTO.getOrderNumber());
        //这个地方实际可优化减小消息体积，目前不做处理
        message.setBody(JSON.toJSONString(addOrderResponseDTO).getBytes(StandardCharsets.UTF_8));
        ResponseData<SendResult> responseData = messageServiceClient.pushSyncMessage0(message);
        if (responseData.getCode() != Code.Success) {
            return ReturnResult.fail("呼叫失败，请重试！");
        }
        // 再发送一条延迟消息，如果订单在一定时间内还是不能派单就将状态变成已取消
        PushOrderRequestDTO delayRequest = new PushOrderRequestDTO();
        delayRequest.setTopic("ClearTimeoutCall");
        delayRequest.setLevel(17);
        delayRequest.setOrderNumber(addOrderResponseDTO.getOrderNumber());
        ResponseData<SendResult> delayResult = messageServiceClient.pushSyncDelayOrder(delayRequest);
        if (delayResult.getCode() != Code.Success) {
            logger.error("订单过期清除延迟消息发送失败！");
        }
        return ReturnResult.success().setData(addOrderResponseDTO);
    }

    /**
     * @Author huchenying
     * @Description 更改上车位置 ，延时双删缓存
     * @Date 2022/3/24 14:41
     **/
    @PostMapping("/upDateOriginPoint")
    public ReturnResult upDateOriginPoint(@Validated @RequestBody UpdateOrderOriginPointRequestDTO requestDTO) throws InterruptedException {
        logger.info("upDateOriginPoint start param -> {}", ToStringBuilder.reflectionToString(requestDTO));
        redisUtils.removeOrderCache(requestDTO.getOrderNumber());
        ResponseData<SimpleOrderResponseDTO> responseData = orderBaseClient.upDateOriginPoint(requestDTO);
        Thread.sleep(100);
        redisUtils.removeOrderCache(requestDTO.getOrderNumber());
        if (responseData.getCode() == Code.Success && responseData.getData().getStatus() >= OrderStatus.RECV.getCode()) {
            //发消息通知司机
            /**
             * @Author huchenying
             * @Description 优化
             * @Date 2022/4/12 17:06
             **/
            pushMessage(Clients.DRIVER, responseData.getData().getPassengerPhone(), requestDTO, M_Code.OrderOriginPointChange);
//            MyWebSocketMessage myWebSocketMessage = new MyWebSocketMessage();
//            myWebSocketMessage.setUsername(responseData.getData().getPassengerPhone());
//            myWebSocketMessage.setClientId(Clients.DRIVER.getName());
//            myWebSocketMessage.setCode(M_Code.OrderOriginPointChange.getCode());
//            myWebSocketMessage.setDesc(M_Code.OrderOriginPointChange.getDesc());
//            myWebSocketMessage.setData(requestDTO);
//            Message message = new Message();
//            message.setTopic("WEBSOCKET");
//            //这个地方实际可优化减小消息体积，目前不做处理
//            message.setBody(JSON.toJSONString(myWebSocketMessage).getBytes(StandardCharsets.UTF_8));
////            ResponseData<SendResult> responseData1 = messageServiceClient.pushSyncMessage0(message);
//            if(responseData1.getCode() != Code.Success){
//                return ReturnResult.fail("更新失败！请重试！");
//            }
            return ReturnResult.success().setData(responseData.getData());
        } else {
            return ReturnResult.fail("更新失败！请重试！");
        }
    }

    /**
     * @Author huchenying
     * @Description 乘客取消订单，只能在上车之前取消
     * @Date 2022/4/12 16:28
     **/
    @PostMapping("/cancelOrder")
    public ReturnResult cancelOrder(@Validated @RequestBody CancelOrderRequestDTO requestDTO) {
        logger.info("cancelOrder start param -> {}", ToStringBuilder.reflectionToString(requestDTO));
        //更改订单状态
        ResponseData<SimpleOrderResponseDTO> responseData = orderBaseClient.customerCancelOrder(requestDTO);
        if (responseData.getCode() == Code.Success) {
            SimpleOrderResponseDTO data = responseData.getData();
            if (data.getDriverId() != null) { //需要告知司机
                //实时
                pushMessage(Clients.DRIVER, data.getDriverPhone(), new Object(), M_Code.OrderCancelMessage);
                //消息
                PushMsgRequestDTO pushMsgRequestDTO = new PushMsgRequestDTO();
                pushMsgRequestDTO.setTypeId(PushMsg.Order.getCode());
                pushMsgRequestDTO.setType(PushMsg.Order.getName());
                pushMsgRequestDTO.setMaster(Master.Driver.getCode());
                pushMsgRequestDTO.setDriverName(data.getDriverPhone());
                pushMsgRequestDTO.setContent("订单 " + data.getOrderNumber() + "已被乘客取消");
                pushMsgRequestDTO.setTime(new Date());
                ResponseData<Object> responseData1 = commonInfoClient.pushMessage(pushMsgRequestDTO);
                if(responseData1.getCode() != Code.Success){
                    logger.warn("消息push失败");
                }
                //释放运力
                redisUtils.removeDriverRev(data.getDriverPhone());
            }

            return ReturnResult.success();
        }
        return ReturnResult.fail(responseData.getMsg());
    }

    /**
     * @Author huchenying
     * @Description 发送webSocket消息
     * @Date 2022/4/12 16:58
     **/
    public boolean pushMessage(Clients clients, String username, Object data, M_Code m_code) {
        //发消息通知司机
        MyWebSocketMessage myWebSocketMessage = new MyWebSocketMessage();
        myWebSocketMessage.setUsername(username);
        myWebSocketMessage.setClientId(clients.getName());
        myWebSocketMessage.setCode(m_code.getCode());
        myWebSocketMessage.setDesc(m_code.getDesc());
        myWebSocketMessage.setData(data);
        Message message = new Message();
        message.setTopic("WEBSOCKET");
        //这个地方实际可优化减小消息体积，目前不做处理
        message.setBody(JSON.toJSONString(myWebSocketMessage).getBytes(StandardCharsets.UTF_8));
        ResponseData<SendResult> responseData = messageServiceClient.pushSyncMessage0(message);
        return responseData.getCode() == Code.Success;
    }
}
